﻿using System;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Daemon;
using JetBrains.ReSharper.Daemon.Stages;
using JetBrains.ReSharper.Daemon.Stages.Dispatcher;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;
using JetBrains.ReSharper.Psi.Tree;
using SPCAFContrib.Entities.Consts;
using SPCAFContrib.ReSharper.Common;
using SPCAFContrib.ReSharper.Common.Attributes;
using SPCAFContrib.ReSharper.Common.CodeAnalysis;
using SPCAFContrib.ReSharper.Common.Extensions;
using SPCAFContrib.ReSharper.Consts;
using SPCAFContrib.ReSharper.Inspection.Code;

[assembly: RegisterConfigurableSeverity(DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting.CheckId,
  null,
  Consts.CORRECTNESS_GROUP,
  DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting.CheckId + ": " + DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting.Message,
  "SPContentType contains two collections, Fields (of type SPFieldCollection) and FieldLinks (of type SPFieldLinkCollection). Even if the object model appears to support addition or deletion of fields using the Fields collection, an exception is thrown if you try to do so.",
  Severity.ERROR,
  false, Internal = false)]

namespace SPCAFContrib.ReSharper.Inspection.Code
{
    [ElementProblemAnalyzer(new[] { typeof(IReferenceExpression) }, HighlightingTypes = new[] { typeof(DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting) })]
    [Applicability(
        IDEProjectType.SP2010FarmSolution |
        IDEProjectType.SPSandbox |
        IDEProjectType.SP2013FarmSolution |
        IDEProjectType.SPServerAPIReferenced)]
    public class DoNotUseSPContentTypeFieldsToAddOrDelete : ElementProblemAnalyzer<IReferenceExpression>
    {
        protected override void Run(IReferenceExpression element, ElementProblemAnalyzerData analyzerData, IHighlightingConsumer consumer)
        {
            IPsiSourceFile sourceFile = element.GetSourceFile();

            if (sourceFile != null)
            {
                if (sourceFile.HasExcluded(analyzerData.SettingsStore)) return;

                IProject project = sourceFile.GetProject();

                if (project != null)
                {
                    if (project.IsApplicableFor(this))
                    {
                        if (IsInvalid(element))
                        {
                            consumer.AddHighlighting(new DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting(element),
                                element.GetDocumentRange(),
                                element.GetContainingFile());
                        }
                    }
                }
            }
        }

        public static bool IsInvalid(IReferenceExpression element)
        {
            bool result = false;
            IExpressionType expressionType = element.GetExpressionType();
            if (expressionType.IsResolved &&
                element.IsResolvedAsPropertyUsage(ClrTypeKeys.SPContentType,
                    new[] {"Fields"}))
            {
                ICSharpExpression containingExpression = element.GetContainingExpression();
                if (containingExpression is IReferenceExpression)
                {
                    IReferenceExpression parentExpression = containingExpression as IReferenceExpression;
                    result = parentExpression.IsResolvedAsMethodCall(ClrTypeKeys.SPFieldCollection,
                        new[] {new MethodCriteria() {ShortName = "Add"}, new MethodCriteria() {ShortName = "Delete"}});
                }
            }

            return result;
        }
    }

    [ConfigurableSeverityHighlighting(CheckId, CSharpLanguage.Name, OverlapResolve = OverlapResolveKind.NONE, ShowToolTipInStatusBar = true)]
    public class DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting : IHighlighting
    {
        public const string CheckId = CheckIDs.Rules.Assembly.DoNotUseSPContentTypeFieldsToAddOrDelete;
        public const string Message = "Do not use SPContentType.Fields collection to add or delete items";

        public IReferenceExpression Element { get; private set; }
        public DoNotUseSPContentTypeFieldsToAddOrDeleteHighlighting(IReferenceExpression element)
        {
            this.Element = element;
        }

        #region IHighlighting Members

        public string ToolTip
        {
            get
            {
                return String.Format("{0}: {1}", CheckId, Message);
            }
        }
        public string ErrorStripeToolTip
        {
            get { return ToolTip; }
        }

        public int NavigationOffsetPatch
        {
            get { return 0; }
        }

        public bool IsValid()
        {
            return this.Element != null && this.Element.IsValid();
        }

        #endregion
    }
}
